use anyhow::Result;
use crossterm::event::{Event as CrosstermEvent, EventStream};
use futures::StreamExt;
use libc::{SIGHUP, SIGINT, SIGQUIT, SIGTERM};
use tokio::{select, sync::{mpsc::{self, Receiver, Sender}, oneshot}, task::JoinHandle};

use crate::core::Event;

/// 负责系统信号的监听 将其转化为应用的内部信号
/// SIGHUP  SIGTERM SIGINT SIGQUIT 
/// 用户输入处理 使用crossterm监听键盘时间和窗口大小调整事件
/// 提供开关接口 stop_term 可以动态开启或者禁用终端的事件监听
/// 
/// 通过mpsc通道实现事件的发布和订阅模式
/// 通过oneshot通道控制中断事件
pub struct Signals {
	pub tx: Sender<Event>,  // 事件发送端
	pub rx: Receiver<Event>,  // 事件接收端 

	term_stop_tx: Option<oneshot::Sender<()>>, // 监听停止信号发送端
	term_stop_rx: Option<oneshot::Receiver<()>>, // 监听停止信号接收端
}

impl Signals {
	pub fn start() -> Result<Self> {
		let (tx, rx) = mpsc::channel(500);  // 创建容量为500的多生产者单消费者通道
		let (term_tx, term_rx) = oneshot::channel(); // 创建一次性通道 用于发送停止信号

		let mut signals =
			Self { 
                tx: tx.clone(), 
                rx, 
                term_stop_tx: Some(term_tx), 
                term_stop_rx: Some(term_rx) 
            };

		signals.spawn_system_task()?;  // 启动系统信号监听任务
		signals.spawn_crossterm_task(); // 启动终端事件监听任务  

		Event::init(tx); // 初始化事件系统
		Ok(signals)
	}

	fn spawn_system_task(&self) -> Result<JoinHandle<()>> {
		let tx = self.tx.clone();
        // 使用signal hook tokio监听系统信号 
        
		let mut signals = signal_hook_tokio::Signals::new([SIGHUP, SIGTERM, SIGINT, SIGQUIT])?;

        // 将捕获的信号转成Event Quit
		Ok(tokio::spawn(async move {
			while let Some(signal) = signals.next().await {
				match signal {
					SIGHUP | SIGTERM | SIGINT | SIGQUIT => {
						if tx.send(Event::Quit).await.is_err() {
							break;
						}
					}
					_ => {}
				}
			}
		}))
	}
    
    // 终端事件监听任务  
	fn spawn_crossterm_task(&mut self) -> JoinHandle<()> {
		let tx = self.tx.clone();
		let mut stop_rx = self.term_stop_rx.take().unwrap();

		tokio::spawn(async move {
			let mut reader = EventStream::new();

			loop {
				select! {
					_ = &mut stop_rx => break, // 收到停止信号退出循环
					Some(Ok(event)) = reader.next() => {
						let event = match event {  // 只关注键盘事件和窗口大小变化事件
							CrosstermEvent::Key(key) => Event::Key(key),
							CrosstermEvent::Resize(cols, rows) => Event::Resize(cols, rows),
							_ => continue, // 忽略其他事件  如鼠标事件等
						};
						if tx.send(event).await.is_err() {
							break;
						}
					}
				}
			}
		})
	}

	pub fn stop_term(&mut self, state: bool) {
		if state == self.term_stop_tx.is_none() {
			return;  // 状态已经符合要求  无需操作
		}

		if let Some(tx) = self.term_stop_tx.take() {
			tx.send(()).ok();  // 发送停止信号
		} else {
			let (tx, rx) = oneshot::channel();
			(self.term_stop_tx, self.term_stop_rx) = (Some(tx), Some(rx));
			self.spawn_crossterm_task();  // 重启监听任务
		}
	}
}
